﻿// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision$</version>
// </file>

using System;
using System.Collections.Generic;

namespace ICSharpCode.TextEditor.Document
{
    /// <summary>
    /// A simple folding strategy which calculates the folding level
    /// using the indent level of the line.
    /// </summary>
    public class CSharpFoldingStrategy : IFoldingStrategy
    {
        int GetLevel(IDocument document, int offset)
        {
            int level = 0;
            int spaces = 0;
            for (int i = offset; i < document.TextLength; ++i)
            {
                char c = document.GetCharAt(i);
                if (c == '\t' || (c == ' ' && ++spaces == 4))
                {
                    spaces = 0;
                    ++level;
                }
                else
                {
                    break;
                }
            }
            return level;
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document)
        {
            List<FoldMarker> list = new List<FoldMarker>();

            Stack<int> startLines = new Stack<int>();
            Stack<string> startTextLines = new Stack<string>();

            bool summaryState = false;
            string summaryText = string.Empty; 

            // Create foldmarkers for the whole document, enumerate through every line.
            for (int i = 0; i < document.TotalNumberOfLines; i++)
            {
                char c;          
                int offs, end = document.TextLength;
                LineSegment seg = document.GetLineSegment(i);             

                for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++)
                {
                    //offs 增加
                }
                if (offs == end)
                    break;
                int spaceCount = offs - seg.Offset;

                // now offs points to the first non-whitespace char on the line

                int start = 0;
                char dott = document.GetCharAt(offs);
                string text = document.GetText(offs, seg.Length - spaceCount);

                if (!string.IsNullOrEmpty(text))
                {
                    switch (dott)
                    {
                        case '#':

                            if (text.StartsWith("#region"))
                            {
                                startLines.Push(i);
                                startTextLines.Push(text);                                
                            }
                            if (text.StartsWith("#endregion") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();

                                string regionLabel = startTextLines.Pop();
                                string regionText = regionLabel.Replace("#region", "").Trim();

                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length - regionLabel.Length,
                                    i, spaceCount + "#region".Length + "endregion".Length + regionLabel.Length,
                                    FoldType.Region, regionText)); 
                              
                             }

                            break;

                        case '/':
                            
                            if (text.StartsWith("/// <summary>"))
                            {
                                startLines.Push(i);
                                summaryText = "";
                                summaryState = true;
                            }

                            if (string.IsNullOrEmpty(summaryText) && !text.StartsWith("/// <summary>")
                                && !text.StartsWith("/// </summary>"))
                            {
                                summaryText += text.Replace("///", "").Trim();                              
                            }
                            
                            if (text.StartsWith("/// </summary>") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length - "/// <summary>".Length,
                                    i, spaceCount + "/// <summary>".Length + "/// </summary>".Length,
                                    FoldType.Region, string.Format("/// <summary> {0} ", summaryText)));

                                summaryState = false;
                            }

                            //update by wxdong 2018-01-25
                            if (list.Count > 0)
                            {
                                var region = list[list.Count - 1];
                                if (text.StartsWith("/// <param"))
                                {
                                    list[list.Count - 1].ReConstruct(region.StartLine,
                                    region.StartColumn,
                                    i, spaceCount + text.Length,
                                    FoldType.Region, region.FoldText+"...");
                                }
                                if (text.StartsWith("/// <returns>"))
                                {
                                    list[list.Count - 1].ReConstruct(region.StartLine,
                                    region.StartColumn,
                                    i, spaceCount + text.Length,
                                    FoldType.Region, region.FoldText);
                                }
                            }
                          

                            break;

                        case '{':
                        case '}':

                            text = document.GetText(offs, seg.Length - spaceCount);
                            if (text.StartsWith("{"))
                                startLines.Push(i);
                            if (text.StartsWith("}") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop() - 1;
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length,
                                    i, spaceCount + "}".Length));
                            }

                            break;

                    }

                }


            }

            return list;
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
        {
            List<FoldMarker> list = new List<FoldMarker>();

            Stack<int> startLines = new Stack<int>();
            Stack<string> startTextLines = new Stack<string>();

            // Create foldmarkers for the whole document, enumerate through every line.
            for (int i = 0; i < document.TotalNumberOfLines; i++)
            {
                var seg = document.GetLineSegment(i);
                int offs, end = document.TextLength;
                char c;
                for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++)
                {
                    //offs 增加
                }
                if (offs == end)
                    break;
                int spaceCount = offs - seg.Offset;

                // now offs points to the first non-whitespace char on the line

                int start = 0;
                char dott = document.GetCharAt(offs);
                string text = document.GetText(offs, seg.Length - spaceCount);

                if (!string.IsNullOrEmpty(text))
                {
                    switch (dott)
                    {
                        case '#':

                            if (text.StartsWith("#region"))
                            {
                                startLines.Push(i);
                                startTextLines.Push(text);                                
                            }
                            if (text.StartsWith("#endregion") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();

                                string regionLabel = startTextLines.Pop();
                                string regionText = regionLabel.Replace("#region", "").Trim();

                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length - regionLabel.Length,
                                    i, spaceCount + "#region".Length + "endregion".Length + regionLabel.Length,
                                    FoldType.Region, regionText)); 
                              
                             }

                            break;

                        case '/':

                            if (text.StartsWith("/// <summary>"))
                                startLines.Push(i);
                            if (text.StartsWith("/// </summary>") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length,
                                    i, spaceCount + "/// </summary>".Length));
                            }

                            break;

                        case '{':
                        case '}':

                            text = document.GetText(offs, seg.Length - spaceCount);
                            if (text.StartsWith("{"))
                                startLines.Push(i);
                            if (text.StartsWith("}") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop() - 1;
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length,
                                    i, spaceCount + "}".Length));
                            }

                            break;

                    }

                }


            }

            return list;
        }

    }
}
